package com.flyway.service.impl;

import com.flyway.exceptions.MyException;
import com.flyway.pojo.captcha.ImageVerificationDto;
import com.flyway.pojo.captcha.ImageVerificationVo;
import com.flyway.service.CaptchaService;
import com.flyway.utils.HttpContextUtils;
import com.flyway.utils.ImageVerificationUtil;
import com.flyway.utils.UuidUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Random;

@Service
@Slf4j
public class CaptchaServiceImpl implements CaptchaService {

    /**
     * 源图路径前缀
     */
    @Value("${captcha.slide-verification-code.path.origin-image}")
    private String verificationImagePathPrefix;

    /**
     * 模板图路径前缀
     */
    @Value("${captcha.slide-verification-code.path.template-image}")
    private String templateImagePathPrefix;

    /**
     * 获取request对象
     * @return 返回request对象
     */
    /*protected static HttpServletRequest getRequest() {
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    }*/

    /**
     * 获取response对象
     * @return 返回response对象
     */
    /*protected static HttpServletResponse getResponse() {
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
    }*/

    /**
     * 获取滑动验证码
     * @param imageVerificationDto 验证码参数
     * @return 滑动验证码
     */
    @Override
    public ImageVerificationVo selectSlideVerificationCode(ImageVerificationDto imageVerificationDto) {


        ImageVerificationVo imageVerificationVo = null;
        try {
//            //  原图路径，这种方式不推荐。当运行jar文件的时候，路径是找不到的，我的路径是写到配置文件中的。
//            String verifyImagePath = URLDecoder.decode(this.getClass().getResource("/").getPath() + "static/targets", "UTF-8");

//            获取模板文件，。推荐文件通过流读取， 因为文件在开发中的路径和打成jar中的路径是不一致的
//            InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("static/template/1.png");
            File verifyImageImport = new File(verificationImagePathPrefix);
            File[] verifyImages = verifyImageImport.listFiles();

            Random random = new Random(System.currentTimeMillis());
            //  随机取得原图文件夹中一张图片
            File originImageFile = verifyImages[random.nextInt(20)];

            //  获取模板图片文件
            File templateImageFile = new File(templateImagePathPrefix + "/template.png");

            //  获取描边图片文件
            File borderImageFile = new File(templateImagePathPrefix + "/border.png");
            //  获取描边图片类型
            String borderImageFileType = borderImageFile.getName().substring(borderImageFile.getName().lastIndexOf(".") + 1);

            //  获取原图文件类型
            String originImageFileType = originImageFile.getName().substring(originImageFile.getName().lastIndexOf(".") + 1);
            //  获取模板图文件类型
            String templateImageFileType = templateImageFile.getName().substring(templateImageFile.getName().lastIndexOf(".") + 1);

            //  读取原图
            BufferedImage verificationImage = ImageIO.read(originImageFile);
            //  读取模板图
            BufferedImage readTemplateImage = ImageIO.read(templateImageFile);

            //  读取描边图片
            BufferedImage borderImage = ImageIO.read(borderImageFile);


            //  获取原图感兴趣区域坐标
            imageVerificationVo = ImageVerificationUtil.generateCutoutCoordinates(verificationImage, readTemplateImage);

            int y  = imageVerificationVo.getY();
            //  在分布式应用中，可将session改为redis存储
            HttpContextUtils.getHttpServletRequest().getSession().setAttribute("imageVerificationVo", imageVerificationVo);
            String uuid = UuidUtil.get32UUID();
            //RedisUtil.setAttrRedisObject("img:code:" + uuid,imageVerificationVo,60);
            //  根据原图生成遮罩图和切块图
            imageVerificationVo = ImageVerificationUtil.pictureTemplateCutout(originImageFile, originImageFileType, templateImageFile, templateImageFileType, imageVerificationVo.getX(), imageVerificationVo.getY());

            //   剪切图描边
            imageVerificationVo = ImageVerificationUtil.cutoutImageEdge(imageVerificationVo, borderImage, borderImageFileType);
            imageVerificationVo.setY(y);
            imageVerificationVo.setToken(uuid);
            imageVerificationVo.setType(imageVerificationDto.getType());

        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new MyException(e.getMessage());
        }

        return imageVerificationVo;
    }

    /**
     * 滑动验证码验证方法
     *
     * @param token
     * @param x x轴坐标
     * @param y y轴坐标
     * @return 滑动验证码验证状态
     */
    @Override
    public boolean checkVerificationResult(String token, String x, String y) throws MyException {

        int threshold = 5;

        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            ImageVerificationVo imageVerificationVo = (ImageVerificationVo) request.getSession().getAttribute("imageVerificationVo");
            //ImageVerificationVo imageVerificationVo = RedisUtil.getAttrRedisObject("img:code:" + token);
            if (imageVerificationVo != null) {
                if ((Math.abs(Integer.parseInt(x) - imageVerificationVo.getX()) <= threshold) && y.equals(String.valueOf(imageVerificationVo.getY()))) {
                    return true;
                } else {
                    return false;
                }
            } else {
                return false;
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new MyException(e.getMessage());
        }
    }
}
